package com.atguigu.tingshu.album.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tencentcloudapi.vod.v20180717.VodClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

	@Autowired
	private TrackInfoMapper trackInfoMapper;
    @Autowired
    private AlbumInfoMapper albumInfoMapper;
    @Autowired
    private TrackStatMapper trackStatMapper;
    @Autowired
    private AlbumStatMapper albumStatMapper;
    @Autowired
    private UserFeignClient userFeignClient;
    @Autowired
    private VodService vodService;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveTrackInfo(TrackInfoVo trackInfoVo,Long userId) {

        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
        TrackInfo trackInfo = BeanUtil.copyProperties(trackInfoVo, TrackInfo.class);
        trackInfo.setUserId(userId);
        trackInfo.setOrderNum(albumInfo.getIncludeTrackCount()+1);
        trackInfo.setStatus(SystemConstant.TRACK_STATUS_PASS);
        String mediaFileId = trackInfo.getMediaFileId();
        TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(mediaFileId);
        if (trackInfo != null) {
            trackInfo.setMediaDuration(new BigDecimal(trackMediaInfoVo.getDuration()));
            trackInfo.setMediaSize(trackMediaInfoVo.getSize());
            trackInfo.setMediaUrl(trackMediaInfoVo.getMediakUrl());
            trackInfo.setMediaType(trackMediaInfoVo.getType());
        }

        trackInfoMapper.insert(trackInfo);
        Long trackId = trackInfo.getId();
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount()+1);
        albumInfo.setUpdateTime(new Date());
        albumInfoMapper.updateById(albumInfo);

        saveTrackStat(trackId,SystemConstant.TRACK_STAT_PLAY,0);
        saveTrackStat(trackId,SystemConstant.TRACK_STAT_COLLECT,0);
        saveTrackStat(trackId,SystemConstant.TRACK_STAT_PRAISE,0);
        saveTrackStat(trackId,SystemConstant.TRACK_STAT_COMMENT,0);
    }

    @Override
    public Page<TrackListVo> getUserTrackPage(Page<TrackListVo> trackInfoVoPage, TrackInfoQuery trackInfoQuery) {
        return trackInfoMapper.getUserTrackPage(trackInfoVoPage, trackInfoQuery);
    }

    @Override
    public Page<AlbumTrackListVo> findAlbumTrackPage(Long userId, Long albumId, Page<AlbumTrackListVo> trackListPage) {

        Page<AlbumTrackListVo> albumTrackList = trackInfoMapper.selectTrackByAlbumId(albumId, trackListPage);

        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        String payType = albumInfo.getPayType();

        if (userId == null) {

            if (payType.equals(SystemConstant.ALBUM_PAY_TYPE_VIPFREE) || payType.equals(SystemConstant.ALBUM_PAY_TYPE_REQUIRE)) {

                albumTrackList.getRecords()
                              .stream()
                              .filter(albumTrack -> albumTrack.getOrderNum() > albumInfo.getTracksForFree())
                              .forEach(waitForCheckTrack -> waitForCheckTrack.setIsShowPaidMark(true));

            }

        } else {
            boolean isNeedCheckPayStatus = false;

            if (payType.equals(SystemConstant.ALBUM_PAY_TYPE_VIPFREE)) {

                UserInfoVo userInfoVo = userFeignClient.getUserInfoVo(userId).getData();
                Assert.notNull(userInfoVo,"获取用户信息失败，用户Id:{}",userId);
                Integer isVip = userInfoVo.getIsVip();

                if (isVip.intValue() == 0) {
                    isNeedCheckPayStatus = true;
                }
                if (isVip.intValue() == 1 && new Date().after(userInfoVo.getVipExpireTime())) {
                    isNeedCheckPayStatus = true;
                }

            }

            if (payType.equals(SystemConstant.ALBUM_PAY_TYPE_REQUIRE)) {
                isNeedCheckPayStatus = true;
            }

            if (isNeedCheckPayStatus) {

                List<AlbumTrackListVo> waitCheckTracks = albumTrackList.getRecords()
                        .stream()
                        .filter(albumTrack -> albumTrack.getOrderNum() > albumInfo.getTracksForFree())
                        .collect(Collectors.toList());

                List<Long> waitCheckIds = waitCheckTracks
                        .stream()
                        .map(albumTrackVo -> albumTrackVo.getTrackId())
                        .collect(Collectors.toList());

                Map<Long, Integer> payResultMap = userFeignClient.userIsPaidTrack(userId, albumId, waitCheckIds).getData();
                Assert.notNull(payResultMap, "获取用户{}已购专辑、声音数据异常,专辑Id:{}", userId, albumId);

                waitCheckTracks.forEach(waitForCheckTrack -> {
                    Integer isPay = payResultMap.get(waitForCheckTrack.getTrackId());
                    if (isPay == 0) {
                        waitForCheckTrack.setIsShowPaidMark(true);
                    }
                });
            }

        }


        return albumTrackList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTrackStat(TrackStatMqVo trackStatVo) {

        String businessNo = trackStatVo.getBusinessNo();
        String lockKey = "MQ:" + businessNo;
        Boolean flag = redisTemplate.opsForValue().setIfAbsent(lockKey, businessNo, 1, TimeUnit.HOURS);

        if (flag){

            try {
                Long trackId = trackStatVo.getTrackId();
                Long albumId = trackStatVo.getAlbumId();
                Integer count = trackStatVo.getCount();
                String statType = trackStatVo.getStatType();

                trackInfoMapper.updateTrackStat(trackId,count,statType);  // 传的type就是声音的type

                if (statType.equals(SystemConstant.TRACK_STAT_PLAY)){
                    albumStatMapper.updateAlbumStat(albumId,count,SystemConstant.ALBUM_STAT_PLAY);
                }


                if (statType.equals(SystemConstant.TRACK_STAT_COMMENT)){
                    albumStatMapper.updateAlbumStat(albumId,count,SystemConstant.ALBUM_STAT_COMMENT);
                }
            } catch (Exception e) {
                redisTemplate.delete(lockKey); // 进这里说明确实出现异常,需要重试,如果不删下次重试时无法执行业务
                throw new RuntimeException(e); // 将异常抛给调用者Listener
            }

        }

    }

    @Override
    public TrackStatVo getTrackStatVo(Long trackId) {
        TrackStatVo trackStatVo = trackStatMapper.selectTrackStat(trackId);
        return trackStatVo;
    }


    public void saveTrackStat(Long trackId,String statTyp,Integer statNum){
        TrackStat trackStat = new TrackStat();
        trackStat.setTrackId(trackId);
        trackStat.setStatType(statTyp);
        trackStat.setStatNum(statNum);
        trackStatMapper.insert(trackStat);
    }
}

